/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-12-08 11:05:53
 * @LastEditors: zhl
 * @LastEditTime: 2022-02-08 13:30:50
 * @Description: 串口代理
 */
#include <utility>
#include <functional>
#include "SerialProxy.h"
#include "CLogger.h"
#include "common.h"


#define REQUEST_TOPIC(APPNAME, PORT)   APPNAME "/uartManager/JSON/transparant/notification/"+PORT+"/data"
#define RESPONSE_TOPIC(APPNAME, PORT)  "uartManager/" APPNAME "/JSON/transparant/notification/"+PORT+"/data"



SerialProxy::SerialProxy(std::shared_ptr<CConfigManager> global_conf, std::string&& if_addr) noexcept : c_if_addr(std::move(if_addr)){
    c_global_conf = global_conf;
    init();
}
SerialProxy::~SerialProxy(){
}
//
void SerialProxy::init(){
    c_rep = NULL;
    c_rep_len = 0;
    c_req_id = 0;
    get_if_port();
    init_mqtt();
}
//
void SerialProxy::get_if_port(){
    auto interface =  c_global_conf->get_interfaces()->find(c_if_addr);
    if(interface == c_global_conf->get_interfaces()->end()){
        return ;
    }
    c_if_port = interface->second;
}
//
void SerialProxy::set_serial_params(SERIAL_PARAMS&& params) noexcept{
    c_serial_params  = params;
}
//
int  SerialProxy::subscribe_topic(){
    std::string topic = RESPONSE_TOPIC("pemd", c_if_port);
    return c_mosquitto_manager->subscribe(topic.c_str());
}

void SerialProxy::init_mqtt(){
    c_mosquitto_manager = std::make_shared<CMosquittoManager>();
    c_mosquitto_manager->init(this, std::bind(&SerialProxy::recv_msg_callback, 
                                              this, 
                                              std::placeholders::_1, 
                                              std::placeholders::_2, 
                                              std::placeholders::_3, 
                                              std::placeholders::_4, 
                                              std::placeholders::_5));
    
}
int  SerialProxy::connect(const char *host, int port, const char * username, const char *password, int keepalive){
    if((NULL == host) || (1 > strlen(host))){
        return MOSQ_ERR_INVAL;
    }
    int ret = c_mosquitto_manager->connect(host, port, username, password, keepalive);
    if(MOSQ_ERR_SUCCESS == ret){
        c_mosquitto_manager->start();
    }else{
        c_mosquitto_manager->stop();
    }
    return ret;
}
void SerialProxy::finish_signal(){
    c_thread_notify.lock();
    c_is_receiving = false;
    c_thread_notify.signal();
    c_thread_notify.unlock();
}
void SerialProxy::wait_recv_finished(uint32_t timeout){
    if(ETIMEDOUT == c_thread_notify.timewait(timeout)){
        c_rep_len = 0;
    }
}
int SerialProxy::send_msg(uint8_t *req, int req_len, uint8_t *rep, int &rep_len, uint32_t timeout){
    c_thread_notify.lock();
    if((NULL == req) || (1 > req_len) || (NULL == rep) || (1 > rep_len)){
        c_thread_notify.unlock();
        return -1;
    }
    int count = 0;
    c_rep_len = rep_len;
    c_rep = rep;
    c_req_id++;
    std::string msg = "";
    std::string topic = REQUEST_TOPIC("pemd",c_if_port);
    c_spm.get_serial_request_msg(c_if_port, c_req_id, c_serial_params, (char *)req, req_len, msg, timeout);
    CLogger::getInstance()->log_i("发送数据: %s", msg.c_str());
    int ret = c_mosquitto_manager->publish(topic.c_str(), msg.length(), msg.c_str());
    if(ret == MOSQ_ERR_SUCCESS){
        c_is_receiving = true;
        //执行2遍等待
        while(2 > count){
            count++;
            wait_recv_finished(timeout+1000);
            if(c_spm.c_token == c_req_id){
                break;
            }
            c_rep_len = 0;
        }
        rep_len = c_rep_len;
    }else{
        rep_len = 0;
    }

    if(c_spm.c_token == c_req_id){
        if(-1 == rep_len){
            CLogger::getInstance()->log_i("收到串口代理应答,无数据: token(%d)", c_spm.c_token);
        } else {
            CLogger::getInstance()->log_i("收到串口代理应答: token(%d)", c_spm.c_token);
        }
    } else {
        if(0 == rep_len){
            CLogger::getInstance()->log_i("接收数据超时: token(%d); req_id(%d)", c_spm.c_token, c_req_id);
        } else if(-1 == rep_len){
            CLogger::getInstance()->log_i("接收数据超时,串口代理应答异常: token(%d); req_id(%d)", c_spm.c_token, c_req_id);
        } else {
            CLogger::getInstance()->log_i("接收到非法数据: token(%d); req_id(%d)", c_spm.c_token, c_req_id);
        }
    }

    c_thread_notify.unlock();
    return c_rep_len;
}
int SerialProxy::recv_msg_callback(CALLBACK_TYPE cb_type, void *data, int data_len, int result, void *arg){
    CLogger::getInstance()->log_d("任务线程回调方法(type: %d)", cb_type);
    if(NULL == data){
        return -1;
    }
    if(CALLBACK_TYPE_MESSAGE == cb_type){
        //handle_request_msg((char *)data);
        //处理消息，需要支持分帧处理。
        if(NULL != data){
            struct mosquitto_message *msg = (struct mosquitto_message *)data;
            //发送收到数据信号
            CLogger::getInstance()->log_i("接收到topic:%s", msg->topic);
            CLogger::getInstance()->log_i("接收到数据:%s", msg->payload);
            std::string data = (char *)msg->payload;
            c_spm.get_serial_response_msg(data, (char *)c_rep, c_rep_len);
            int n = 0;
            while(!c_is_receiving){
                n++;
                if(n > 5){
                    break;
                }
                millisecond_sleep(50);
            }
            if(n < 6){
                finish_signal();
            }
        }
    } else if(CALLBACK_TYPE_CONNECTED == cb_type){
        subscribe_topic();
    }

    return result;
}